package com.fdb.efp.nls.service.impl.queue;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

import com.fdb.efp.nls.service.facade.NlsApplyInfoService;
import com.fdb.efp.nls.service.facade.SoltService;
import com.fdb.efp.nls.service.facade.queue.NlsProcessBizService;
import com.fdb.efp.nls.service.facade.queue.NlsProcessRuleService;
import com.fdb.efp.nls.service.facade.queue.NlsQueueTaskService;
import com.fdb.efp.nls.service.vo.NlsApplyInfoVO;
import com.fdb.efp.nls.service.vo.queue.NlsProcessBizVO;
import com.fdb.efp.nls.service.vo.queue.NlsProcessRuleVO;
import org.apache.logging.log4j.ThreadContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.fdb.basic.framework.core.exception.BizException;
import com.fdb.basic.framework.core.exception.HangException;
import com.fdb.basic.framework.core.threadpool.AbstractThreadTask;
import com.fdb.basic.framework.core.threadpool.ExecuteRtnInfo;
import com.fdb.basic.framework.core.util.DateUtility;
import com.fdb.basic.framework.core.util.SpringContextUtils;
import com.fdb.basic.framework.core.util.TraceUtil;
import com.fdb.efp.nls.service.facade.PrdAdaptedSoltService;
import com.fdb.efp.nls.service.vo.PrdAdaptedSoltVO;
import com.fdb.efp.esb.common.constant.MsLoanConstant;
import com.fdb.efp.nls.common.constant.PrdAdaptedSoltEnums;
import com.fdb.efp.nls.common.constant.QueueTaskEnums;

/**
 * ServiceImpl:网贷队列处理类
 * 
 * @author huangwb
 * @since 2019年1月7日 上午11:54:02
 * @version 1.0
 */
@Service("queueHangHandleService")
@Scope(scopeName = "prototype")
public class QueueHangHandle extends AbstractThreadTask {
	private static Logger logger = LoggerFactory.getLogger(QueueHangHandle.class);

	private NlsApplyInfoVO nlsApplyInfoVO;

	public void setNlsApplyInfoVO(NlsApplyInfoVO nlsApplyInfoVO) {
		this.nlsApplyInfoVO = nlsApplyInfoVO;
	}

	@Override
	public ExecuteRtnInfo call() throws Exception {
		this.doTask();
		return new ExecuteRtnInfo(null, null, null, null, true);
	}

	/**
	 * @description:挂起处理逻辑
	 * @throws HangException
	 * @throws BizException
	 * @throws Exception
	 * @date:2019年2月22日 下午4:08:04
	 * @author:wangyk3
	 */

	@Override
	public void doTask() throws HangException, BizException, Exception {
		TraceUtil.setTraceId(nlsApplyInfoVO.getGlobalSerno());
		TraceUtil.setPlafmID(nlsApplyInfoVO.getPlatfmId());
		TraceUtil.setPlafmUsrID(nlsApplyInfoVO.getPlatfmUsrID());
		ThreadContext.put(TraceUtil.GLBLSRLNO, nlsApplyInfoVO.getGlobalSerno());
		TraceUtil.setGlblSrlNo(nlsApplyInfoVO.getGlobalSerno());
		logger.info("*********************************************");
		logger.info("*            开始一笔挂起执行队列                 * ");
		logger.info("*********************************************");
		logger.info("* 申请流水号:【" + nlsApplyInfoVO.getApplySeq() + "】*");
		logger.info("* 客户编号 : 【" + nlsApplyInfoVO.getCusId() + "】*");
		logger.info("* 客户名称 : 【" + nlsApplyInfoVO.getCusName() + "】*");
		logger.info("* 产品ID:  【" + nlsApplyInfoVO.getPrdId() + "】*");
		logger.info("* 产品代码: 【" + nlsApplyInfoVO.getPrdCode() + "】*");
		logger.info("* 产品名称 : 【" + nlsApplyInfoVO.getPrdName() + "】*");
		logger.info("* 创建时间 : 【" + nlsApplyInfoVO.getCreateTime() + "】*");
		logger.info("*********************************************");
		String applySeq = nlsApplyInfoVO.getApplySeq();
		try {
			logger.info("根据产品ID和插槽状态查询产品插槽信息");
			PrdAdaptedSoltVO prdAdaptedSoltVo = new PrdAdaptedSoltVO();
			prdAdaptedSoltVo.setPrdId(nlsApplyInfoVO.getPrdId());
			prdAdaptedSoltVo.setSoltStage(nlsApplyInfoVO.getSoltStage());
			prdAdaptedSoltVo.setSoltState(PrdAdaptedSoltEnums.SlotStateEnum.ON.getCode());// 插槽状态
			List<PrdAdaptedSoltVO> prdAdaptedSoltVoList = prdAdaptedSoltService.queryByPrdIdAndState(prdAdaptedSoltVo);
			Objects.requireNonNull(prdAdaptedSoltVoList);

			logger.info("根据申请流水号:【" + applySeq + "】查询网贷业务过程信息");
			NlsProcessBizVO nlsProcessBizVo = new NlsProcessBizVO();
			nlsProcessBizVo.setApplySeq(applySeq);
			nlsProcessBizVo = nlsProcessBizService.queryByPk(nlsProcessBizVo);
			Objects.requireNonNull(nlsProcessBizVo);
			logger.info("根据申请流水号:【" + applySeq + "】查询网贷业务过程信息,挂起次数为：" + nlsProcessBizVo.getHangTimes());

			logger.info("申请流水号:【" + applySeq + "】的遍历产品插槽的信息开始");
			for (int i = 0; i < prdAdaptedSoltVoList.size(); i++) {
				PrdAdaptedSoltVO prdAdaptedSolt = prdAdaptedSoltVoList.get(i);
				String soltCode = prdAdaptedSolt.getSoltCode();
				String soltName = prdAdaptedSolt.getSoltName();
				String soltService = prdAdaptedSolt.getSoltService();// 插槽服务类
				int soltOrder = prdAdaptedSolt.getSoltOrder();

				// 根据插槽代码 映射
				Method methodSoltName = nlsProcessBizVo.getClass().getMethod("setSoltName" + soltOrder, String.class);
				Method methodSoltTime = nlsProcessBizVo.getClass().getMethod("setSoltTime" + soltOrder, String.class);
				Method methodSoltstate = nlsProcessBizVo.getClass().getMethod("setSoltState" + soltOrder, String.class);
				Method methodSoltstateForGet = nlsProcessBizVo.getClass().getMethod("getSoltState" + soltOrder);
				String state = (String) methodSoltstateForGet.invoke(nlsProcessBizVo);
				logger.info("根据插槽代码 ：【" + soltCode + "】映射处理类");
				if (state.equals(PrdAdaptedSoltEnums.SoltProcessStateEnum.HANG.getCode())) {
					logger.info("该插槽代码 ：【" + soltCode + "】的插槽过程状态为：【" + PrdAdaptedSoltEnums.SoltProcessStateEnum.HANG.getDesc() + "】");
					logger.info("更新挂起次数在原有次数上加1，且更新该插槽状态为待执行");
					// 更新该插槽状态为待执行
					methodSoltstate.invoke(nlsProcessBizVo, PrdAdaptedSoltEnums.SoltProcessStateEnum.EXECUTORY.getCode());
					nlsProcessBizService.updateByPk(nlsProcessBizVo);
				} else if (state.equals(PrdAdaptedSoltEnums.SoltProcessStateEnum.EXECUTORY.getCode())) {
					logger.info("该插槽代码 ：【" + soltCode + "】的插槽过程状态为：【" + PrdAdaptedSoltEnums.SoltProcessStateEnum.EXECUTORY.getDesc() + "】，无须处理！");
				} else {
					logger.info("该插槽代码 ：【" + soltCode + "】的插槽过程状态为：【" + state + "】，无须处理开始下一插槽！");
					continue;
				}

				nlsProcessBizVo.setSoltCode(soltCode);// 插槽代码
				nlsProcessBizVo.setSoltName(soltName);// 插槽名称
				nlsProcessBizVo.setSoltService(soltService);// 插槽服务类
				nlsProcessBizVo.setExceptionFlag(Boolean.FALSE);// 异常标志
				nlsProcessBizVo.setQueueTaskState(QueueTaskEnums.QueueTaskStateEnum.EXECUTING.getCode());
				nlsProcessBizService.updateByPk(nlsProcessBizVo);

				// 更新当前插槽代码、当前插槽名称
				/** 当前插槽代码 */
				nlsApplyInfoVO.setSoltCode(soltCode);
				/** 当前插槽名称 */
				nlsApplyInfoVO.setSoltName(soltName);
				/** 插槽名称 */
				methodSoltName.invoke(nlsProcessBizVo, soltName);
				/** 插槽开始时间 */
				methodSoltTime.invoke(nlsProcessBizVo, DateUtility.getCurrAppDateTimeString());
				/** 更新申请进件信息 */
				nlsApplyInfoService.updateByPk(nlsApplyInfoVO);

				logger.info("根据插槽服务 ：【" + soltService + "】映射处理Bean开始");
				SoltService slotServiceBean = (SoltService) SpringContextUtils.getBean(soltService);
				logger.info("根据插槽服务 ：【" + soltService + "】映射处理Bean结束，该对象为：【" + slotServiceBean + "】，调用对应的服务开始。");
				slotServiceBean.execute(nlsProcessBizVo, nlsApplyInfoVO, soltOrder);
				logger.info("根据插槽服务 ：【" + soltService + "】映射处理Bean结束，该对象为：【" + slotServiceBean + "】，调用对应的服务结束。");
			}
			logger.info("申请流水号:【" + applySeq + "】的遍历产品插槽的信息结束");

			logger.info("根据申请流水号:【" + applySeq + "】更新业务流程表队列任务状态为执行成功开始");
			nlsProcessBizVo.setQueueTaskState(QueueTaskEnums.QueueTaskStateEnum.SUCCESS.getCode());

			logger.info("根据申请流水号:【" + applySeq + "】更新网贷任务队列中队列任务状态为执行成功开始");
			/** 查询规则过程信息 **/
			NlsProcessRuleVO nlsProcessRuleVO = new NlsProcessRuleVO();
			nlsProcessRuleVO.setApplySeq(applySeq);
			nlsProcessRuleVO = nlsProcessRuleService.queryByPk(nlsProcessRuleVO);

			/** 设置插槽结果信息 **/
			nlsApplyInfoVO.setSoltResultDetails(JSONObject.toJSONString(nlsProcessBizVo));
			/** 设置规则结果信息 **/
			nlsApplyInfoVO.setRuleResultDetails(JSONObject.toJSONString(nlsProcessRuleVO));
			/** 设置结果码 **/
			nlsApplyInfoVO.setRspCode(QueueTaskEnums.RspInfoEnum.SUCCESS.getRspCode());
			/** 设置结果信息 **/
			nlsApplyInfoVO.setRspMsg(QueueTaskEnums.RspInfoEnum.SUCCESS.getRspMsg());
			/** 设置申请状态信息为通过 **/
			nlsApplyInfoVO.setNlsApplyState(MsLoanConstant.NlsApplyStateEnum.PASS.getVALUE());
			/** 设置申请最近修改时间 **/
			nlsApplyInfoVO.setLastModifyTime(DateUtility.getCurrAppDateTimeString());// 最近修改时间

			nlsApplyInfoService.updateByPk(nlsApplyInfoVO);
			logger.info("根据申请流水号:【" + applySeq + "】更新 申请进件信息中申请状态为通过结束");
			nlsProcessBizService.updateByPk(nlsProcessBizVo);
			logger.info("根据申请流水号:【" + applySeq + "】更新业务流程表队列任务状态为执行成功结束");
		} catch (HangException e) {
			logger.error("队列处理服务中申请流水号:【" + applySeq + "】的挂起异常信息为：" + e.getMessage());
			throw e;
		} catch (BizException e) {
			logger.error("队列处理服务中申请流水号:【" + applySeq + "】的业务异常信息为：" + e.getMessage());
			throw e;
		} catch (Exception e) {
			logger.error("队列处理服务中申请流水号:【" + applySeq + "】的其他异常信息为：" + e.getMessage());
			throw e;
		} finally {
			TraceUtil.clear();
		}
	}

	@Autowired
	@Qualifier("nlsQueueTaskService")
	private NlsQueueTaskService nlsQueueTaskService;
	@Autowired
	@Qualifier("prdAdaptedSoltService")
	private PrdAdaptedSoltService prdAdaptedSoltService;
	@Autowired
	@Qualifier("nlsProcessBizService")
	private NlsProcessBizService nlsProcessBizService;
	@Autowired
	@Qualifier("nlsApplyInfoService")
	private NlsApplyInfoService nlsApplyInfoService;
	@Autowired
	@Qualifier("nlsProcessRuleService")
	private NlsProcessRuleService nlsProcessRuleService;

}
